﻿#include "scene.h"

#include <math.h>

#include <QGraphicsSceneMouseEvent>
#include <QList>
#include <QMessageBox>
#include <QTimer>

#include "../tool/abstracttool.h"
#include "../tool/toolmanager.h"
#include "building.h"
#include "feature.h"
#include "floor.h"
#include "imagelayer.h"
#include "pubpoint.h"
#include "room.h"

#if defined(Q_CC_MSVC)
#pragma execution_character_set("utf-8")
#endif

Scene::Scene(QObject *parent)
    : QGraphicsScene(parent), m_selectable(true), m_root(NULL),
      m_building(NULL), m_curFloor(NULL), m_scaleSum(0.0), m_scaleNum(0),
      m_curScale(1.0) {
  createRoot();
}

void Scene::reset() {
  QGraphicsScene::clear(); // Removes and deletes all items from the scene
  m_root = NULL;
  m_building = NULL;
  Floor::resetMaxFloorId();
  createRoot();
  setBuilding(new Building(tr("未命名建筑")));
  setSelectedLayer(m_building);
  update();
}

Feature *Scene::root() const { return m_root; }

void Scene::createRoot() {
  if (m_root != NULL) {
    deleteMapFeature(m_root);
    m_root = NULL;
  }
  m_root = new Feature(tr("root")); // add a root node
  addItem(m_root);
}

Building *Scene::building() const { return m_building; }

void Scene::setBuilding(Building *building) {
  if (m_building == building)
    return;
  if (m_building != NULL) { // delete the old one
    deleteMapFeature(m_building);
    m_building = NULL;
  }

  m_building = building;
  m_building->setParentFeature(m_root);
}

PolygonFeature *Scene::createPolygonByContext() {
  Feature *curLayer = currentLayer();
  if (curLayer != NULL) {
    if (curLayer->isClassOf("Building")) {
      Building *building = dynamic_cast<Building *>(curLayer);
      if (building->outline().empty()) {
        return building;
      } else {
        return addFloor(new Floor(m_building));
      }
    } else if (curLayer->isClassOf("Floor")) {
      Floor *floor = dynamic_cast<Floor *>(curLayer);
      if (floor->outline().empty()) {
        return floor;
      } else {
        return addRoom(new Room(floor));
      }
    } else {
      return addRoom(new Room(m_curFloor));
    }
  }

  return NULL;
}

void Scene::deletePolygonByContext(PolygonFeature *feature) {
  feature->removeAllPoint();
  if (feature->isClassOf("Room")) {
    deleteMapFeature(feature);
    emit buildingChanged();
  } else if (feature->isClassOf("Floor")) {
    if (m_building) {
      Floor *floor = dynamic_cast<Floor *>(feature);
      m_building->deleteFloor(floor);
    } else {
      deleteMapFeature(feature);
    }
    emit buildingChanged();
  }

  update();
}

Room *Scene::addRoom(Room *room) {
  if (m_curFloor != NULL) {
    room->setParentFeature(m_curFloor);
    emit buildingChanged();
    return room;
  }

  delete room;

  return NULL;
}

Floor *Scene::addFloor(Floor *floor) {
  if (m_building != NULL) {
    if (floor) {
      m_building->addFloor(floor);
    } else {
      floor = new Floor();
      m_building->addFloor(floor);
    }
    m_curFloor = floor;
    setSelectedLayer(floor);
    emit buildingChanged();
    return floor;
  }

  delete floor;

  return NULL;
}

void Scene::addPubPoint(PubPoint *pubPoint) {
  if (m_curFloor != NULL) {
    pubPoint->setParentFeature(m_curFloor);
  } else {
    pubPoint->setParentFeature(m_building);
  }
  emit buildingChanged();
}

void Scene::addImageLayer(ImageLayer *imageLayer) {
  //    if(m_curFloor != NULL) {
  //        imageLayer->setParentFeature(m_curFloor);
  //    }else{

  //    }
  Floor *floor = new Floor();
  imageLayer->setParentFeature(floor);
  addFloor(floor);
}

void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event) {
  ToolManager::instance()->currentTool().mousePressEvent(event);
  if (m_selectable && event->button() == Qt::LeftButton)
    QGraphicsScene::mousePressEvent(event);
}

void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
  ToolManager::instance()->currentTool().mouseReleaseEvent(event);
  if (m_selectable && event->button() == Qt::LeftButton)
    QGraphicsScene::mouseReleaseEvent(event);
}

void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
  if (m_selectable)
    QGraphicsScene::mouseMoveEvent(event);
  ToolManager::instance()->currentTool().mouseMoveEvent(event);
}

bool Scene::event(QEvent *event) {
  if (event->type() == QEvent::FontChange) {
    emit fontChanged(font());
  }
  return QGraphicsScene::event(event);
}

void Scene::setSelectable(bool b) { m_selectable = b; }

void Scene::convertSelectedToBuilding() {
  PolygonFeature *selectedFeature =
      dynamic_cast<PolygonFeature *>(selectedItems().at(0));
  if (selectedFeature == NULL) {
    return;
  }
  m_building->copy(*selectedFeature);

  //如果是floor或building，仅清空其轮廓
  if (selectedFeature->isClassOf("Floor") ||
      selectedFeature->isClassOf("Building")) {
    PolygonFeature *poly = dynamic_cast<PolygonFeature *>(selectedFeature);
    poly->removeAllPoint();
  } else { //否则直接删除
    deleteMapFeature(selectedFeature);
  }
  emit buildingChanged();
}

void Scene::convertSelectedToFloor() {
  PolygonFeature *selectedFeature =
      dynamic_cast<PolygonFeature *>(selectedItems().at(0));
  if (selectedFeature == NULL) {
    return;
  }
  if (m_curFloor != NULL && m_curFloor->outline().empty()) {
    m_curFloor->setOutline(selectedFeature->outline());
  } else {
    addFloor(new Floor(*selectedFeature));
  }

  //如果是floor或building，仅清空其轮廓
  if (selectedFeature->isClassOf("Floor") ||
      selectedFeature->isClassOf("Building")) {
    PolygonFeature *poly = dynamic_cast<PolygonFeature *>(selectedFeature);
    poly->removeAllPoint();
  } else { //否则直接删除
    deleteMapFeature(selectedFeature);
  }
  emit buildingChanged();
}

void Scene::convertSelectedToRoom() {
  PolygonFeature *selectedFeature =
      dynamic_cast<PolygonFeature *>(selectedItems().at(0));
  if (selectedFeature == NULL) {
    return;
  }
  addRoom(new Room(*selectedFeature));
  selectedFeature->removeAllPoint();
}

void Scene::deleteSelectedItems() {
  QList<QGraphicsItem *> items = selectedItems();
  QList<QGraphicsItem *> realItems;
  QList<QGraphicsItem *>::iterator iter;
  for (iter = items.begin(); iter != items.end(); iter++) {
    (*iter)->setSelected(false);
    if (!qgraphicsitem_cast<QGraphicsTextItem *>(*iter)) {
      realItems.append(*iter);
    }
  }
  foreach (QGraphicsItem *item, realItems) {
    Feature *mapFeature = dynamic_cast<Feature *>(item);
    if (mapFeature != NULL) {
      //如果是floor或building，仅清空其轮廓
      // if (mapFeature->isClassOf("Floor") ||
      // mapFeature->isClassOf("Building")) {
      //  PolygonFeature *poly = dynamic_cast<PolygonFeature *>(mapFeature);
      //  poly->removeAllPoint();
      //} else { //否则直接删除
      deleteMapFeature(mapFeature);
      //}
      emit buildingChanged();
    }
  }
  update();
}

void Scene::deleteSelectedLayers() {
  bool isBuilding = false;
  foreach (QGraphicsItem *item, m_selectedLayers) {
    if (item != NULL) {
      Feature *mapFeature = qgraphicsitem_cast<Feature *>(item);
      if (mapFeature->isClassOf("Building")) {
        isBuilding = true;
      }

      if ((m_building != NULL) && mapFeature->isClassOf("Floor")) {
        Floor *floor = dynamic_cast<Floor *>(mapFeature);
        m_building->deleteFloor(floor);
      } else {
        deleteMapFeature(mapFeature);
      }
    }
  }
  if (isBuilding) {
    reset();
  }
  clearSelectedLayers();
}

void Scene::deleteMapFeature(Feature *feature) {
  if (feature == NULL) {
    return;
  }

  removeMapFeature(feature);
  delete feature;
}

void Scene::removeMapFeature(Feature *feature) {
  if (feature == NULL) {
    return;
  }

  /* clear */
  if (feature == m_curFloor) {
    m_curFloor = NULL;
  }
  if (feature == currentLayer()) {
    clearSelectedLayers();
  }

  feature->setParent(NULL);
  /* If newParent is 0, this item will become a top-level item. */
  // feature->setParentItem(NULL);
  QGraphicsScene::removeItem(feature);
}

bool Scene::showFloor(int floorId) {
  Building *curr_building = building();
  if (curr_building == NULL) {
    return false;
  }

  bool found = false;
  QVector<Floor *> floors = curr_building->getFloors();
  if (floors.empty()) {
    return false;
  }

  foreach (Floor *floor, floors) {
    if (floor->id() == floorId) {
      floor->setVisible(true);
      setCurrentFloor(floor);
      found = true;
    } else {
      floor->setVisible(false);
    }
  }

  if (!found) { //如果没找到对应的defaultFloor
    Floor *floor = floors.at(0);
    if (floor == NULL) {
      return false;
    }
    floor->setVisible(true);
    setCurrentFloor(floor);
  }
  update();

  return true;
}

bool Scene::showDefaultFloor() {
  Building *curr_building = building();
  if (curr_building == NULL) {
    return false;
  }

  int defaultFloorId = curr_building->defaultFloor();
  return showFloor(defaultFloorId);
}

void Scene::setCurrentFloor(Floor *floor) { m_curFloor = floor; }

Floor *Scene::currentFloor() const { return m_curFloor; }

void Scene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
  ToolManager::instance()->currentTool().contextMenuEvent(event);
}

QList<Feature *> Scene::findMapFeature(const QString &name) {
#if 0
    //TODO: better stategies
    return m_root->findChildren<Feature*>(name);
#else
  QList<Feature *> featureList;

  QList<QGraphicsItem *> items = this->items();
  foreach (QGraphicsItem *item, items) {
    Feature *feature = dynamic_cast<Feature *>(item);
    if (feature == NULL) {
      continue;
    }

    if (feature->objectName() == name) {
      featureList.append(feature);
    }
  }

  return featureList;
#endif
}

QList<QList<Feature *>> Scene::findAllRepeat() {
  QList<QList<Feature *>> result;
  QHash<QString, Feature *> hash;
  if (m_building != NULL) {
    const QVector<Floor *> &floors = m_building->getFloors();
    Floor *floor;
    foreach (floor, floors) {
      Q_ASSERT_X(floor != NULL, "findAllRepeat", "floor is NULL");
      Room *room;
      const QList<Room *> &rooms = floor->getRooms();
      foreach (room, rooms) {
        QString name = room->objectName();
        if (name.compare("非开放区域") && name.compare("中空") &&
            name.compare("空铺")) {
          hash.insertMulti(room->objectName(), room);
        }
      }
    }
  }

  const QList<QString> &keys = hash.uniqueKeys();
  foreach (const QString &key, keys) {
    const QList<Feature *> &list = hash.values(key);
    if (list.size() > 1) {
      result.append(list);
    }
  }

  return result;
}

void Scene::selectMapFeature(Feature *feature) {
  if (feature != NULL &&
      (feature->isClassOf("Room") || feature->isClassOf("PubPoint"))) {
    clearSelection();
    Floor *floor = dynamic_cast<Floor *>(feature->parentObject());
    if (floor != NULL) {
      showFloor(floor->id());
    }
    feature->setSelected(true);
  }
}

void Scene::transformMap(const QMatrix &mat) {
  if (m_curFloor != NULL) { // rotate current floor
    m_curFloor->transformFeature(mat);
  } else if (m_building != NULL) { // rotate the whole building
    m_building->transformFeature(mat);
  }
}

void Scene::addScale(double s) {
  m_scaleNum++;
  double scale = (s * m_curScale + m_curScale * (m_scaleNum - 1)) /
                 m_scaleNum; //相对于初始的平均缩放
  QMatrix mat;
  scale /= m_curScale; //相对于上一次的缩放
  if (qFuzzyIsNull(scale)) {
    return;
  }
  mat.scale(scale, scale);
  m_building->transformFeature(mat);
  m_curScale = scale;
}

void Scene::setSelectedLayer(Feature *feature) {
  m_selectedLayers.clear();
  m_selectedLayers.append(feature);
}

void Scene::clearSelectedLayers() { m_selectedLayers.clear(); }

Feature *Scene::currentLayer() {
  if (m_selectedLayers.empty())
    return NULL;
  else
    return m_selectedLayers.back();
}
